﻿using System;
using System.Collections.Generic;
using System.Data.SqlClient;
using System.Text;
using Microsoft.SharePoint.Administration;
using Microsoft.SharePoint.Administration.Health;

namespace SPHealth.SharePoint.HealthRules.SP.Rules.Performance
{
    public class WarnMaxDegreeParallelism : SPHealthAnalysisRule
    {
        #region Locals
        private string _failingServers;
        private const string GET_MAX_DEGREE_PARALLELISM = @" select value_in_use from sys.configurations where name = 'max degree of parallelism' ";
        private SPHealthAnalysisRuleAutomaticExecutionParameters _executionParameters;
        #endregion

        #region Constructor
        /* not required */
        #endregion

        #region Fields

        public override string Summary
        {
            get { return "SQL Server instances that host SharePoint databases should have max degree of parallelism (MAXDOP) set to 1."; }
        }

        public override string Explanation
        {
            get
            {
                return string.Format("The following SQL Instance(s) have an incorrectly configured max degree of parallelism:\r\n{0}",_failingServers);
            }
        }

        public override string Remedy
        {
            get { return "Set max degree of parallelism (MAXDOP) to 1 for SQL Server instances that host SharePoint Server 2010 " +
                    "databases to ensure that each request is served by a single SQL Server process. " +
                    "In a SharePoint Server environment, any other setting will result in a sub-optimal query plan being selected for execution, " +
                    "which will decrease overall performance. See http://technet.microsoft.com/en-us/library/hh292622.aspx"; }
        }

        public override SPHealthCheckErrorLevel ErrorLevel
        {
            get { return SPHealthCheckErrorLevel.Warning; }
        }

        public override SPHealthCategory Category
        {
            get { return SPHealthCategory.Performance; }
        }

        public override SPHealthAnalysisRuleAutomaticExecutionParameters AutomaticExecutionParameters
        {
            get
            {
                if (_executionParameters == null)
                {
                    _executionParameters = new SPHealthAnalysisRuleAutomaticExecutionParameters
                    {
                        Schedule = SPHealthCheckSchedule.Daily,
                        Scope = SPHealthCheckScope.Any,
                        ServiceType = typeof(SPTimerService), //Tell SP if we want our own timer job or can we run with others...
                        RepairAutomatically = false
                    };
                }
                return _executionParameters;
            }
        }

        #endregion

        #region Methods

        public override SPHealthCheckStatus Check()
        {
            if (!SPFarm.Joined)
            {
                throw new InvalidOperationException();
            }

            SPHealthCheckStatus status = SPHealthCheckStatus.Passed;
            _failingServers = "";

            // create a list of every unique server that sharepoint is using as a database server
            Dictionary<string, string> dbServers = new Dictionary<string, string>();

            // populate the list of unique servers
            foreach (SPServer server in SPFarm.Local.Servers)
            {
                SPDatabaseServiceInstanceCollection instances = new SPDatabaseServiceInstanceCollection(server);
                foreach (SPDatabaseServiceInstance instance in instances)
                {
                    foreach (SPDatabase database in instance.Databases)
                    {
                        if (!dbServers.ContainsKey(database.Server.Name))
                            dbServers.Add(database.Server.Name, database.DatabaseConnectionString);
                    }
                }

            }

            foreach (string dbServer in dbServers.Keys)
            {
                if (!GetSQLServerMaxDegreeOfParallelism(dbServers[dbServer]))
                    _failingServers += dbServer;
            }

            if(!string.IsNullOrEmpty(_failingServers))
                status = SPHealthCheckStatus.Failed;

            return status;
        }

        private static bool GetSQLServerMaxDegreeOfParallelism(string connectionString)
        {


            using (SqlConnection connection = new SqlConnection(connectionString))
            {
                connection.Open();
                using (SqlCommand command = new SqlCommand { Connection = connection, CommandText = GET_MAX_DEGREE_PARALLELISM })
                {

                    object temp = command.ExecuteScalar();
                    if (temp != null)
                    {
                        if ((int)temp == 1)
                            return true;
                    }
                }
            }

            return false;

        }
        #endregion

    }
}
